# this package holds all shared objects that can be used in both
# the server and the client

# will be copied to the client once the server development is done

from abc import ABCMeta, abstractmethod

# for dumping/loading small objects only
# if ever need to store large objects on disk, use SQLite instead
import pickle


class _ABC_AutoID_(object):
    """
    Abstract Base Class :: Object w/ Auto Increment ID
    
    The subclass also have to define the following methods:
      def getID() return int
    
    The subclass can override the following class methods, but the super
    class version should always be called first:
      def _load_(str)
      def _dump_() return str

    This is a "multiton" class. Any class inherit this one will maintain
    all its instances inside the class itself, so you can access any
    instance from any other instance of the same class:
      class A(_ABC_AutoID_):
        def __init__(self):
          pass

      a1 = A()
      a2 = A()
      a1.getObject(a2.getID()) ==> this return the object a2
    """
    __metaclass__ = ABCMeta     # mark the class as abstract


    _next_id_ = 1000            # start with id 1000
    _obj_dict_ = None           # class level dict of all existing objects

    def __init__(self):
        self._id_ = self.getNextID()

        if type(self)._obj_dict_ is None:       # not init yet
            type(self)._obj_dict_ = { }         #   create class level dict
        type(self)._obj_dict_[self._id_] = self # add to the class lvl dict
        return

    @classmethod
    def getObject(cls, ID):
        return cls._obj_dict_[ID]

    @classmethod
    def getNextID(cls):
        """ get the next available ID """
        rv = cls._next_id_
        cls._next_id_ += 1
        return rv


    ######## interface methods ########

    @abstractmethod
    def getID(self):
        ''' get the ID of this object '''
        return self._id_

    #################################################
    ## the following method should be replaced by  ##
    ## SQLite API when use with larger objects     ##
    #################################################
    @classmethod
    def _dump_(cls):
        """ dump the system objects list into a string """
        return pickle.dumps([ cls._next_id_, cls._obj_dict_ ])

    @classmethod
    def _load_(cls, objDump):
        """ load a dump string back into the system """
        [ cls._next_id_, cls._obj_dict_ ] = pickle.loads(objDump)
        return
